﻿#include	"Engine.Thread.hpp"

namespace Engine { namespace Thread {

	void Thread::Stop() {
		if (_pIns) {
			if (_bJoin && _pIns->joinable()) _pIns->join();
			delete _pIns;
		}
	}

	Pool::Pool(size_t nCapacity)
		: _bValid(true), _nCapacity(nCapacity) {

		for (size_t n = 0; n < nCapacity; ++n) {
			try {
				std::thread * pWorker = new std::thread(&Pool::_WorkerThread, this);
				_qWorkers.push(pWorker);
			} catch (std::runtime_error &) {
				--n;
			}	
		}
	}

	Pool::~Pool() {
		std::unique_lock<std::mutex> iAuto(_iLock);
		_bValid = false;

		while (!_qTasks.empty()) {
			Task * pTask = _qTasks.front();
			_qTasks.pop();
			delete pTask;
		}

		iAuto.unlock();
		_iSignal.notify_all();

		while (!_qWorkers.empty()) {
			std::thread * pWorker = _qWorkers.front();
			_qWorkers.pop();
			if (pWorker->joinable()) pWorker->join();
			delete pWorker;
		}
	}

	void Pool::AddTask(Task * pTask) {
		std::unique_lock<std::mutex> iAuto(_iLock);
		if (!_bValid) return;

		_qTasks.push(pTask);
		iAuto.unlock();
		_iSignal.notify_one();
	}

	void Pool::_WorkerThread() {
		while (true) {
			std::unique_lock<std::mutex> iAuto(_iLock);
			if (!_bValid) break;

			if (_qTasks.empty()) _iSignal.wait(iAuto);
			if (_qTasks.empty()) break;

			Task * pTask = _qTasks.front();
			_qTasks.pop();
			iAuto.unlock();

			pTask->DoJob();
			delete pTask;
		}
	}

	

}}
